#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>

const int N = 5;

template<class T>
class ThreadPool
{
public:
    // 写这些接口的原因：因为线程调用函数在类内定义，所以需要加static去掉this成员，
    // 但又需要使用类内成员，所以只能使用接口
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void threadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    bool taskEmpty()
    {
        return tasks.empty();
    }

    T popTask()
    {
        T t = tasks.front();
        tasks.pop();
        return t;
    }
public:
    ThreadPool(int cap = N)
        : threads(cap)
        , _cap(cap)
    {
        pthread_cond_init(&_cond, nullptr);
        pthread_mutex_init(&_mutex, nullptr);
    }

    static void* threadRoutine(void* args)
    {
        ThreadPool<T>* pool = static_cast<ThreadPool<T>*>(args);

        while(true)
        {
            pool->lock();
            
            while(pool->taskEmpty())
            {
                pool->threadWait();
            }

            T t = pool->popTask();
            pool->unlock();
            std::cout << "Thread " << (num++)%N << ": Get a message " << t << std::endl;
            usleep(200);
        }
    }

    void start()
    {
        for(int i = 0; i < _cap; i++)
            pthread_create(&threads[i], nullptr, threadRoutine, this); // ??
    }

    void PushTask(const T& in)
    {
        lock();

        tasks.push(in);
        threadWakeup();

        unlock();
    }

    ~ThreadPool()
    {
        for(auto th: threads)
            pthread_join(th, nullptr);

        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mutex);
    }

    static int num;
private:
    std::vector<pthread_t> threads;
    
    std::queue<T> tasks;
    int _cap;

    pthread_cond_t _cond;
    pthread_mutex_t _mutex;
};